﻿using EMall.IdentityService.IdentityServers;
using EMall.IdentityService.Menus;
using EMall.IdentityService.PermissionGrants;
using EMall.IdentityService.Roles;
using EMall.IdentityService.Users;
using IdentityServer4.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace EMall.IdentityService
{
    public class DataSeed
    {
        private readonly IdentityServiceDbContext _dbContext;
        private readonly UserManager<User> _userManager;
        private readonly RoleManager<Role> _roleManager;
        private readonly MenuManager _menuManager;
        public DataSeed(IServiceProvider serviceProvider)
        {
            _dbContext = serviceProvider.GetService<IdentityServiceDbContext>()!;
            _userManager = serviceProvider.GetService<UserManager<User>>()!;
            _roleManager = serviceProvider.GetService<RoleManager<Role>>()!;
            _menuManager = serviceProvider.GetService<MenuManager>()!;
        }
        public void Initialize()
        {
            Migrator();
            DefaultData();
        }
        private void Migrator()
        {
            _dbContext.Database.Migrate();
        }
        private void DefaultData()
        {
            var defaultMenus = _dbContext.Menus.ToList();
            if (!defaultMenus.Any())
            {
                var system = new Menu("系统管理", _menuManager.GenerateCodeAsync(0).Result, MenuType.Module, 0, true, "System", "/system");
                _dbContext.Menus.Add(system); _dbContext.SaveChanges();
                #region Menu
                var menu = new Menu("菜单管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "Menu", "/menu");
                _dbContext.Menus.Add(menu); _dbContext.SaveChanges();
                var menu_List = new Menu("菜单列表", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Page, menu.Id, true, "Menu.List", "/menuList", "/menu/index");
                _dbContext.Menus.Add(menu_List); _dbContext.SaveChanges();
                var menu_Detail = new Menu("菜单详情", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Button, menu.Id, true, "Menu.Detail", "/menuDetail");
                _dbContext.Menus.Add(menu_Detail); _dbContext.SaveChanges();
                var menu_Create = new Menu("菜单添加", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Button, menu.Id, true, "Menu.Create", "/menuCreate");
                _dbContext.Menus.Add(menu_Create); _dbContext.SaveChanges();
                var menu_Update = new Menu("菜单修改", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Button, menu.Id, true, "Menu.Update", "/menuUpdate");
                _dbContext.Menus.Add(menu_Update); _dbContext.SaveChanges();
                var menu_Delete = new Menu("菜单删除", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Button, menu.Id, true, "Menu.Delete", "/menuDelete");
                _dbContext.Menus.Add(menu_Delete); _dbContext.SaveChanges();
                var menu_Export = new Menu("菜单导出", _menuManager.GenerateCodeAsync(menu.Id).Result, MenuType.Button, menu.Id, true, "Menu.Export", "/menuExport");
                _dbContext.Menus.Add(menu_Export); _dbContext.SaveChanges();
                #endregion
                #region Role
                var role = new Menu("角色管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "Role", "/role");
                _dbContext.Menus.Add(role); _dbContext.SaveChanges();
                var role_List = new Menu("角色列表", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Page, role.Id, true, "Role.List", "/roleList", "/role/index");
                _dbContext.Menus.Add(role_List); _dbContext.SaveChanges();
                var role_Detail = new Menu("角色详情", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Detail", "/roleDetail");
                _dbContext.Menus.Add(role_Detail); _dbContext.SaveChanges();
                var role_Create = new Menu("角色添加", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Create", "/roleCreate");
                _dbContext.Menus.Add(role_Create); _dbContext.SaveChanges();
                var role_Update = new Menu("角色修改", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Update", "/roleUpdate");
                _dbContext.Menus.Add(role_Update); _dbContext.SaveChanges();
                var role_Delete = new Menu("角色删除", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Delete", "/roleDelete");
                _dbContext.Menus.Add(role_Delete); _dbContext.SaveChanges();
                var role_Export = new Menu("角色导出", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Export", "/roleExport");
                _dbContext.Menus.Add(role_Export); _dbContext.SaveChanges();
                var role_Permission = new Menu("角色授权", _menuManager.GenerateCodeAsync(role.Id).Result, MenuType.Button, role.Id, true, "Role.Permission", "/rolePermission");
                _dbContext.Menus.Add(role_Permission); _dbContext.SaveChanges();
                #endregion
                #region User
                var user = new Menu("用户管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "User", "/user", "", "");
                _dbContext.Menus.Add(user); _dbContext.SaveChanges();
                var user_List = new Menu("用户列表", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Page, user.Id, true, "User.List", "/userList", "/user/index", "");
                _dbContext.Menus.Add(user_List); _dbContext.SaveChanges();
                var user_Detail = new Menu("用户详情", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Button, user.Id, true, "User.Detail", "/userDetail");
                _dbContext.Menus.Add(user_Detail); _dbContext.SaveChanges();
                var user_Create = new Menu("用户添加", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Button, user.Id, true, "User.Create", "/userCreate");
                _dbContext.Menus.Add(user_Create); _dbContext.SaveChanges();
                var user_Update = new Menu("用户修改", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Button, user.Id, true, "User.Update", "/userUpdate");
                _dbContext.Menus.Add(user_Update); _dbContext.SaveChanges();
                var user_Delete = new Menu("用户删除", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Button, user.Id, true, "User.Delete", "/userDelete");
                _dbContext.Menus.Add(user_Delete); _dbContext.SaveChanges();
                var user_Export = new Menu("用户导出", _menuManager.GenerateCodeAsync(user.Id).Result, MenuType.Button, user.Id, true, "User.Export", "/userExport");
                _dbContext.Menus.Add(user_Export); _dbContext.SaveChanges();
                #endregion
                #region ApiResource
                var apiResource = new Menu("ApiResource管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "ApiResource", "/apiresource");
                _dbContext.Menus.Add(apiResource); _dbContext.SaveChanges();
                var apiResource_List = new Menu("ApiResource列表", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Page, apiResource.Id, true, "ApiResource.List", "/apiresourceList", "/apiresource/index");
                _dbContext.Menus.Add(apiResource_List); _dbContext.SaveChanges();
                var apiResource_Detail = new Menu("ApiResource详情", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Button, apiResource.Id, true, "ApiResource.Detail", "/apiresourceDetail");
                _dbContext.Menus.Add(apiResource_Detail); _dbContext.SaveChanges();
                var apiResource_Create = new Menu("ApiResource添加", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Button, apiResource.Id, true, "ApiResource.Create", "/apiresourceCreate");
                _dbContext.Menus.Add(apiResource_Create); _dbContext.SaveChanges();
                var apiResource_Update = new Menu("ApiResource修改", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Button, apiResource.Id, true, "ApiResource.Update", "/apiresourceUpdate");
                _dbContext.Menus.Add(apiResource_Update); _dbContext.SaveChanges();
                var apiResource_Delete = new Menu("ApiResource删除", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Button, apiResource.Id, true, "ApiResource.Delete", "/apiresourceDelete");
                _dbContext.Menus.Add(apiResource_Delete); _dbContext.SaveChanges();
                var apiResource_Export = new Menu("ApiResource导出", _menuManager.GenerateCodeAsync(apiResource.Id).Result, MenuType.Button, apiResource.Id, true, "ApiResource.Export", "/apiResourceExport");
                _dbContext.Menus.Add(apiResource_Export); _dbContext.SaveChanges();
                #endregion
                #region ApiScope
                var apiScope = new Menu("ApiScope管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "ApiScope", "/apiscope");
                _dbContext.Menus.Add(apiScope); _dbContext.SaveChanges();
                var apiScope_List = new Menu("ApiScope列表", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Page, apiScope.Id, true, "ApiScope.List", "/apiscopeList", "/apiscope/index");
                _dbContext.Menus.Add(apiScope_List); _dbContext.SaveChanges();
                var apiScope_Detail = new Menu("ApiScope详情", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Button, apiScope.Id, true, "ApiScope.Detail", "/apiscopeDetail");
                _dbContext.Menus.Add(apiScope_Detail); _dbContext.SaveChanges();
                var apiScope_Create = new Menu("ApiScope添加", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Button, apiScope.Id, true, "ApiScope.Create", "/apiscopeCreate");
                _dbContext.Menus.Add(apiScope_Create); _dbContext.SaveChanges();
                var apiScope_Update = new Menu("ApiScope修改", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Button, apiScope.Id, true, "ApiScope.Update", "/apiscopeUpdate");
                _dbContext.Menus.Add(apiScope_Update); _dbContext.SaveChanges();
                var apiScope_Delete = new Menu("ApiScope删除", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Button, apiScope.Id, true, "ApiScope.Delete", "/apiscopeDelete");
                _dbContext.Menus.Add(apiScope_Delete); _dbContext.SaveChanges();
                var apiScope_Export = new Menu("ApiScope导出", _menuManager.GenerateCodeAsync(apiScope.Id).Result, MenuType.Button, apiScope.Id, true, "ApiScope.Export", "/apiScopeExport");
                _dbContext.Menus.Add(apiScope_Export); _dbContext.SaveChanges();
                #endregion
                #region IdentityResource
                var identityResource = new Menu("IdentityResource管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "IdentityResource", "/identityresource");
                _dbContext.Menus.Add(identityResource); _dbContext.SaveChanges();
                var identityResource_List = new Menu("IdentityResource列表", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Page, identityResource.Id, true, "IdentityResource.List", "/identityresourceList", "/identityresource/index");
                _dbContext.Menus.Add(identityResource_List); _dbContext.SaveChanges();
                var identityResource_Detail = new Menu("IdentityResource详情", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Button, identityResource.Id, true, "IdentityResource.Detail", "/identityresourceDetail");
                _dbContext.Menus.Add(identityResource_Detail); _dbContext.SaveChanges();
                var identityResource_Create = new Menu("IdentityResource添加", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Button, identityResource.Id, true, "IdentityResource.Create", "/identityresourceCreate");
                _dbContext.Menus.Add(identityResource_Create); _dbContext.SaveChanges();
                var identityResource_Update = new Menu("IdentityResource修改", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Button, identityResource.Id, true, "IdentityResource.Update", "/identityresourceUpdate");
                _dbContext.Menus.Add(identityResource_Update); _dbContext.SaveChanges();
                var identityResource_Delete = new Menu("IdentityResource删除", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Button, identityResource.Id, true, "IdentityResource.Delete", "/identityresourceDelete");
                _dbContext.Menus.Add(identityResource_Delete); _dbContext.SaveChanges();
                var identityresource_Export = new Menu("IdentityResource导出", _menuManager.GenerateCodeAsync(identityResource.Id).Result, MenuType.Button, identityResource.Id, true, "IdentityResource.Export", "/identityresourceExport");
                _dbContext.Menus.Add(identityresource_Export); _dbContext.SaveChanges();
                #endregion
                #region Client
                var client = new Menu("Client管理", _menuManager.GenerateCodeAsync(system.Id).Result, MenuType.Module, system.Id, true, "Client", "/client");
                _dbContext.Menus.Add(client); _dbContext.SaveChanges();
                var client_List = new Menu("Client列表", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Page, client.Id, true, "Client.List", "/clientList", "/client/index");
                _dbContext.Menus.Add(client_List); _dbContext.SaveChanges();
                var client_Detail = new Menu("Client详情", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Button, client.Id, true, "Client.Detail", "/clientDetail");
                _dbContext.Menus.Add(client_Detail); _dbContext.SaveChanges();
                var client_Create = new Menu("Client添加", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Button, client.Id, true, "Client.Create", "/clientCreate");
                _dbContext.Menus.Add(client_Create); _dbContext.SaveChanges();
                var client_Update = new Menu("Client修改", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Button, client.Id, true, "Client.Update", "/clientUpdate");
                _dbContext.Menus.Add(client_Update); _dbContext.SaveChanges();
                var client_Delete = new Menu("Client删除", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Button, client.Id, true, "Client.Delete", "/clientDelete");
                _dbContext.Menus.Add(client_Delete); _dbContext.SaveChanges();
                var client_Export = new Menu("Client导出", _menuManager.GenerateCodeAsync(client.Id).Result, MenuType.Button, client.Id, true, "Client.Export", "/clientExport");
                _dbContext.Menus.Add(client_Export); _dbContext.SaveChanges();
                #endregion
            }
            var adminRole = _roleManager.FindByNameAsync("admin").Result;
            if (adminRole == null)
            {
                adminRole = new Role("admin", true);
                _roleManager.CreateAsync(adminRole).Wait();
                _dbContext.SaveChanges();
            }
            var adminUser = _userManager.FindByNameAsync("admin").Result;
            if (adminUser == null)
            {
                adminUser = new User("admin", true, "超级管理员", "https://img0.baidu.com/it/u=1167596068,2262066712&fm=253", "84646310@qq.com", "138****9110");
                _userManager.CreateAsync(adminUser, "admin!@#").Wait();
                _userManager.AddToRoleAsync(adminUser, adminRole.Name).Wait();
                _dbContext.SaveChanges();
            }
            var adminRolePermissionGrants = _dbContext.PermissionGrants.Where(o => o.Type == PermissionGrantType.R).ToList();
            if (!adminRolePermissionGrants.Any())
            {
                var menus = _dbContext.Menus.Select(o => o.Id.ToString()).ToList();
                if (menus.Any())
                {
                    var permissionGrants = menus.Select(o => new PermissionGrant(o, PermissionGrantType.R, adminRole.Name));
                    _dbContext.PermissionGrants.AddRange(permissionGrants);
                    _dbContext.SaveChanges();
                }
            }
            var defaultApiResources = _dbContext.ApiResources.ToList();
            if (!defaultApiResources.Any())
            {
                defaultApiResources = new List<IdentityServer4.EntityFramework.Entities.ApiResource>
                {
                    new ApiResource
                    {
                        Name = "IdentityService",
                        Properties =
                        {
                            { "Destinations", "http://localhost:5100,http://localhost:5100" }
                        },
                        Scopes = IdentityServiceDefaults.Scopes
                    }.ToEntity()
                };
                _dbContext.ApiResources.AddRange(defaultApiResources);
                _dbContext.SaveChanges();
            }
            var defaultApiScopes = _dbContext.ApiScopes.ToList();
            if (!defaultApiScopes.Any())
            {
                defaultApiScopes = defaultApiResources.SelectMany(o => o.Scopes.Select(s => new ApiScope($"{s.Scope}").ToEntity())).ToList();
                _dbContext.ApiScopes.AddRange(defaultApiScopes);
                _dbContext.SaveChanges();
            }
            var defaultIdentityResources = _dbContext.IdentityResources.ToList();
            if (!defaultIdentityResources.Any())
            {
                var openId = new IdentityResources.OpenId();
                openId.UserClaims.Add("id");
                var profile = new IdentityResources.Profile();
                profile.UserClaims.Add("username");
                profile.UserClaims.Add("avatar");
                defaultIdentityResources = new List<IdentityServer4.EntityFramework.Entities.IdentityResource>
                {
                    openId.ToEntity(),
                    profile.ToEntity(),
                    new IdentityResources.Phone().ToEntity(),
                    new IdentityResources.Email().ToEntity(),
                    new IdentityResources.Address().ToEntity()
                };
                _dbContext.IdentityResources.AddRange(defaultIdentityResources);
                _dbContext.SaveChanges();
            }
            var defaultClients = _dbContext.Clients.ToList();
            if (!defaultClients.Any())
            {
                var adminUri = "http://localhost:9528";
                var adminClient = new Client
                {
                    ClientId = "admin",
                    ClientName = "Admin Client",
                    ClientSecrets = { new Secret("admin!@#".Sha256()) },
                    AllowedGrantTypes = GrantTypes.Code,
                    AllowedScopes = defaultIdentityResources.Select(o => o.Name).Union(defaultApiScopes.Select(o => o.Name)).ToList(),
                    ClientUri = adminUri,
                    RedirectUris = { $"{adminUri}/signin-oidc" },
                    PostLogoutRedirectUris = { $"{adminUri}/signout-callback-oidc" }
                };
                defaultClients = new List<IdentityServer4.EntityFramework.Entities.Client>
                {
                    adminClient.ToEntity()
                };
                _dbContext.Clients.AddRange(defaultClients);
                _dbContext.SaveChanges();
            }
        }
    }
    public static class DataSeedAppBuilderExtensions
    {
        public static void InitDataSeed(this IApplicationBuilder app)
        {
            new DataSeed(app.ApplicationServices).Initialize();
        }
    }
}
